#include "stdafx.h"
#include "JMutex.h"
#include <process.h>
#include <JeayeSDK/c_debug.h>
#include <JeayeSDK/c_memory.h>
#include <JeayeSDK/JThread.h>

#ifdef _DEBUG
#define new new(__FILE__, __LINE__)
#endif

void c_usleep(int nsec)
{
	LARGE_INTEGER freq = { 0 };
	LARGE_INTEGER tc_start = { 0 };
	LARGE_INTEGER tc_end = { 0 };
	double counter = 0;

	if (!QueryPerformanceFrequency(&freq)) {
		DebugOut(_T("file:[%s(%d) %s]don't support high precision timers\n"),__FILE__,__LINE__,__FUNCTION__);
		Sleep(0);
		return;
	}

	QueryPerformanceCounter(&tc_start);
	while (TRUE) {
		QueryPerformanceCounter(&tc_end);
		counter = (((tc_end.QuadPart - tc_start.QuadPart) * 1000000) / (double)freq.QuadPart);
		if (counter >= (double)nsec)
			break;
	}
}

/* Arguments and callback to setup and run the user thread function */
typedef struct {
	c_thread_callback_t callback;
	void *user_args;
	JSemaphore *wait;
	JThread *info;
} c_thread_args_t;

void  __c_thread_function(void *args);

static DWORD RunThread(void *data)
{
	// Call the thread function!
	__c_thread_function(data);

	// Call endthread!
	_endthreadex(0);

	return 0;
}

/**/
static unsigned __stdcall RunThreadViaBeginThreadEx(void *data)
{
	return (unsigned)RunThread(data);
}

/**/
UINT32  c_get_current_thread_id(void)
{
	return ((UINT32)GetCurrentThreadId());
}

/**/
void  c_wait_thread(JThread *thrd)
{
	if (thrd->m_hHandle != NULL) {
		WaitForSingleObject(thrd->m_hHandle, INFINITE);
		CloseHandle(thrd->m_hHandle);
		thrd->m_iThreadID = 0;
		thrd->m_hHandle = NULL;
	}
}
void  c_wait_thread(JThread *thrd, INT32 *status)
{
	if (thrd) {
		c_wait_thread(thrd);
		if (status) {
			*status = thrd->m_iStatus;
		}
	}
}
/**/
BOOL c_set_thread_priority(HANDLE hThreadHandle,int priority)
{
	if (INVALID_HANDLE_VALUE == hThreadHandle) return FALSE;
	if (!SetThreadPriority(hThreadHandle, priority)) {
		DebugOut(_T("Set Thread Priority Error.\n"));
		return FALSE;
	}
	return TRUE;
}

void  __c_thread_function(void *args)
{
	c_thread_args_t *thread_args = (c_thread_args_t *)args;
	JThread *thrd;
	c_thread_callback_t user_func;
	void *user_args;

	/* Get the thread id */
	thread_args->info->m_iThreadID = c_get_current_thread_id();

	/* Figure out what function to run */
	thrd = thread_args->info;
	user_func = thread_args->callback;
	user_args = thread_args->user_args;

	/* Wake up the parent thread */
	thread_args->wait->Unlock();

	/* Run the function */
	thrd->m_iStatus = user_func(thrd, user_args);
}

void  c_thread_destroy(JThread *pSelf)
{
	if (pSelf) {
		c_wait_thread(pSelf, NULL);
	}
}

JThread::JThread()
{
	m_hHandle = NULL;
}

JThread::~JThread()
{
}

void JThread::set_priority(int priority)
{
	c_set_thread_priority(m_hHandle,priority);
}

BOOL JThread::start_thread(c_thread_callback_t callback, void* args)
{
	c_thread_args_t thread_args;

	m_iStatus = -1;

	/* Set up the arguments for the thread */
	thread_args.callback = callback;
	thread_args.user_args = args;
	thread_args.info = this;
	thread_args.wait = new JSemaphore(0);

	if (thread_args.wait == NULL)  return FALSE;

	/* Create the thread and go! */
	unsigned threadid = 0;
	m_hHandle = (HANDLE)_beginthreadex(NULL, 0, RunThreadViaBeginThreadEx, &thread_args, 0, &threadid);
	m_iThreadID = threadid;

	if (m_hHandle == NULL) {
		DebugOut(_T("Not enough resources to create thread\n"));
	}
	thread_args.wait->Lock();

	delete thread_args.wait;
	return TRUE;
}

void JThread::destroy()
{
	c_thread_destroy(this);
}
